home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 5 / Amiga Tools 5.iso / internet-tools / ipdial / source / ipdial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-16  |  21.7 KB  |  1,066 lines

  1. /**
  2. ***  IPDial - IPDial.c
  3. ***
  4. ***  This is the main part of the program.
  5. ***
  6. ***
  7. ***  This program is free software; you can redistribute it and/or modify
  8. ***  it under the terms of the GNU General Public License as published by
  9. ***  the Free Software Foundation; either version 2 of the License, or
  10. ***  (at your option) any later version.
  11. ***
  12. ***  This program is distributed in the hope that it will be useful,
  13. ***  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ***  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. ***  GNU General Public License for more details.
  16. ***
  17. ***  You should have received a copy of the GNU General Public License
  18. ***  along with this program; if not, write to the Free Software
  19. ***  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. ***
  21. ***  Authors: Jochen Wiedmann <wiedmann@neckar-alb.de>
  22. ***           Stefan Gybas <cab@studbox.uni-stuttgart.de>
  23. **/
  24.  
  25.  
  26.  
  27. /**
  28. ***  Include files
  29. **/
  30. #ifndef IPDIAL_H
  31. #include "IPDial.h"
  32. #endif
  33.  
  34. #include <ctype.h>
  35. #include <clib/alib_protos.h>
  36.  
  37.  
  38.  
  39.  
  40.  
  41. /**
  42. ***  This structure describes one command. All commands are stored
  43. ***  in a table at the end of the file.
  44. **/
  45. struct ScriptLine;
  46. typedef VOID (*CommandFunc) (struct ScriptLine *);
  47. struct Command
  48. { CommandFunc Func;
  49.   STRPTR Name;
  50. };
  51.  
  52.  
  53.  
  54.  
  55.  
  56. /**
  57. ***  Each line of the script file is stored in a structure like below.
  58. **/
  59. struct ScriptLine
  60. { struct MinNode mn;
  61.   ULONG Num;
  62.   CommandFunc CommFunc;
  63.   STRPTR Label;
  64.   STRPTR Args;
  65. };
  66.  
  67.  
  68.  
  69.  
  70.  
  71. /**
  72. ***  Global variables
  73. **/
  74. LONG StatusVar;
  75.  
  76. struct MinList ScriptLineList;
  77.  
  78. struct ScriptLine *CurrentScriptLine;
  79.  
  80. ULONG EchoMode = FALSE;
  81. ULONG VerboseMode = FALSE;
  82.  
  83. STRPTR SerialDeviceName = NULL;
  84.  
  85. struct RDArgs *MainRDArgs = NULL;
  86.  
  87. UBYTE ScratchBuffer[ScBufSize];        /*  temp buffer - use with caution!  */
  88.  
  89. const static char VersTag[] = VERSTAG;
  90.  
  91.  
  92.  
  93.  
  94. /**
  95. ***  This function is used to skip blanks.
  96. **/
  97. STRPTR SkipBlanks(const UBYTE *ptr)
  98.  
  99. { while(*ptr == ' '  ||  *ptr == '\t')
  100.   { ++ptr;
  101.   }
  102.   return((STRPTR) ptr);
  103. }
  104.  
  105.  
  106.  
  107.  
  108.  
  109. /**
  110. ***  This function is used to parse a string for characters like '\r' and
  111. ***  '\n'. $VAR or ${VAR} may be used to insert the value of the local or
  112. ***  environment variable VAR, $$ may be used to insert the '$' character
  113. ***  itself, likewise \\.
  114. ***
  115. ***  Returns a pointer to a string allocated with malloc().
  116. ***  It is the task of the caller, to free() this string.
  117. **/
  118. STRPTR ParseString(const UBYTE *ptr)
  119.  
  120. { STRPTR result;
  121.   STATIC APTR parseBuffer = NULL;
  122.  
  123.   /**
  124.   ***  Be sure, that buffer is valid.
  125.   **/
  126.   if (!parseBuffer  &&  !(parseBuffer = BufferCreate()))
  127.   { PrintError(0, "not enough memory");
  128.   }
  129.  
  130.   /**
  131.   ***  Clear the buffer.
  132.   **/
  133.   BufferClear(parseBuffer);
  134.  
  135.   while(*ptr)
  136.   { if (*ptr == '\\')                  /*  Found "\"  */
  137.     { ++ptr;
  138.       switch(*ptr)
  139.       { case 'r':
  140.           BufferExtend(parseBuffer, (STRPTR) "\r", 1);
  141.           break;
  142.         case 'n':
  143.           BufferExtend(parseBuffer, (STRPTR) "\n", 1);
  144.           break;
  145.         case '0':
  146.         case '1':
  147.         case '2':
  148.         case '3':
  149.         case '4':
  150.         case '5':
  151.         case '6':
  152.         case '7':
  153.           { char c;
  154.  
  155.             c = *ptr - '0';
  156.             if (ptr[1] >= '0'  &&  ptr[1] <= '7')
  157.             { c = (c << 3) + *(++ptr) - '0';
  158.               if (ptr[1] >= '0'  &&  ptr[2] <= '7')
  159.               { c = (c << 3) + *(++ptr) - '0';
  160.               }
  161.             }
  162.             BufferExtend(parseBuffer, (STRPTR) &c, 1);
  163.           }
  164.           break;
  165.         default:
  166.           BufferExtend(parseBuffer, ptr, 1);
  167.           break;
  168.       }
  169.       ++ptr;
  170.     }
  171.     else if (*ptr == '$')              /*  Found "$"  */
  172.     { ++ptr;
  173.       if (*ptr == '$')                 /*  Replace "$$" with "$"  */
  174.       { BufferExtend(parseBuffer, (STRPTR) "$", 1);
  175.         ++ptr;
  176.       }
  177.       else
  178.       { const char* varPtr;
  179.         size_t varLen = 0;
  180.  
  181.         if (*ptr == '{')               /*  Replace "${Var}" with value of  */
  182.         { ++ptr;                       /*  of environment variable Var.    */
  183.           varPtr = (const char*) ptr;
  184.           while (*ptr && *ptr != '}')
  185.           { ++ptr;
  186.             ++varLen;
  187.           }
  188.          if (*ptr == '}')              /*  Skip '}'  */
  189.           { ++ptr;
  190.           }
  191.         }
  192.         else                           /*  Replace "$Var" with value of    */
  193.         { varPtr = (const char*) ptr;  /*  environment variable Var.       */
  194.           while (*ptr  &&  isalnum(*ptr))
  195.           { ++ptr;
  196.             ++varLen;
  197.           }
  198.         }
  199.  
  200.         /* Copy variable name to ScratchBuffer and terminat with NULL */
  201.  
  202.         strncpy(ScratchBuffer, varPtr, varLen);
  203.         ScratchBuffer[varLen] = '\0';
  204.  
  205.         /* Is this legal: var name and result buffer are equal? */
  206.  
  207.         if (GetVar(ScratchBuffer, ScratchBuffer, ScBufSize, 0L) != -1)
  208.         { BufferExtend(parseBuffer, ScratchBuffer, strlen(ScratchBuffer));
  209.         }
  210.       }
  211.     }
  212.     else if (*ptr == '"')              /*  filter extra quotes  */
  213.     { ++ptr;
  214.     }
  215.     else
  216.     { BufferExtend(parseBuffer, ptr, 1);
  217.       ++ptr;
  218.     }
  219.   }
  220.  
  221.   BufferExtend(parseBuffer, (STRPTR) "", 1);
  222.  
  223.   if (!(result = (STRPTR) strdup((char*) BufferBuffer(parseBuffer))))
  224.   { PrintError(0, "not enough memory");
  225.   }
  226.  
  227.   return(result);
  228. }
  229.  
  230.  
  231.  
  232.  
  233.  
  234. /**
  235. ***  This is an empty function. Just to allow lines with labels only.
  236. **/
  237. VOID NoneFunc(struct ScriptLine *line)
  238.  
  239. {
  240. }
  241.  
  242.  
  243.  
  244.  
  245.  
  246. /**
  247. ***  This is the echo function.
  248. **/
  249. VOID EchoFunc(struct ScriptLine *line)
  250.  
  251. { STRPTR args;
  252.  
  253.   if (!StrReadArgs(line->Args, (LONG *) &args, (STRPTR) "TEXT/A/F"))
  254.   { PrintError(line->Num, "argument or memory error");
  255.   }
  256.  
  257.   printf("%s", (char*) ParseString(args));
  258.   fflush(stdout);
  259. }
  260.  
  261.  
  262.  
  263.  
  264.  
  265. /**
  266. ***  This is the device function.
  267. **/
  268. VOID DeviceFunc(struct ScriptLine *line)
  269.  
  270. { struct
  271.   { STRPTR Device;
  272.     LONG *Unit;
  273.     LONG *Baud;
  274.     STRPTR Protocol;
  275.   } args;
  276.  
  277.   if (SerialDeviceName)
  278.   { fprintf(stderr, "Line %ld: device already open, ignoring.\n", line->Num);
  279.   }
  280.   else
  281.   { args.Device = NULL;
  282.     args.Unit = NULL;
  283.     args.Baud = NULL;
  284.     args.Protocol = NULL;
  285.  
  286.     if (!StrReadArgs(line->Args, (LONG *) &args,
  287.                      (STRPTR) "NAME/A,UNIT/K/N,BAUD/K/N,HANDSHAKE"))
  288.     { PrintError(line->Num, "argument or memory error");
  289.     }
  290.  
  291.     if (!(SerialDeviceName = (STRPTR) strdup((char *) args.Device)))
  292.     { PrintError(0, "not enough memory");
  293.     }
  294.  
  295.     if (!SerialOpen(args.Device,
  296.                     args.Unit ? *args.Unit : DEFAULT_UNIT,
  297.                     args.Baud ? *args.Baud : DEFAULT_BAUD,
  298.                     args.Protocol ? args.Protocol : DEFAULT_PROTOCOL))
  299.     { PrintError(line->Num, "unknown protocol");
  300.     }
  301.   }
  302. }
  303.  
  304.  
  305.  
  306.  
  307.  
  308. #ifdef SETCMD
  309.  
  310. /**
  311. ***  This function is used to set the serial.device parameters.
  312. **/
  313. VOID SetFunc(struct ScriptLine *line)
  314.  
  315. { struct
  316.   { ULONG *Baud;
  317.     ULONG *DataBits;
  318.     ULONG *StopBits;
  319.     ULONG *BufSize;
  320.     STRPTR Parity;
  321.     STRPTR Protocol;
  322.   } args;
  323.  
  324.   if (!SerialDeviceName)
  325.   { PrintError(line->Num, "serial device not opened");
  326.   }
  327.  
  328.   args.Baud = NULL;
  329.   args.DataBits = NULL;
  330.   args.StopBits = NULL;
  331.   args.BufSize = NULL;
  332.   args.Parity = NULL;
  333.   args.Protocol = NULL;
  334.  
  335.   if (!(StrReadArgs(line->Args, (LONG *) &args,
  336.                     (STRPTR) "BAUD/K/N,DATABITS/K/N,STOPBITS/K/N,BUFSIZE/K/N,"
  337.                              "PARITY/K,PROTOCOL/K")))
  338.   { PrintError(line->Num, "argument or memory error");
  339.   }
  340.  
  341.   if (args.Baud)
  342.   { SerialSetBaud(*args.Baud);
  343.   }
  344.   if (args.DataBits)
  345.   { SerialSetDataBits(*args.DataBits);
  346.   }
  347.   if (args.StopBits)
  348.   { SerialSetStopBits(*args.StopBits);
  349.   }
  350.   if (args.BufSize)
  351.   { SerialSetBufSize(*args.BufSize);
  352.   }
  353.   if (args.Parity)
  354.   { if (!SerialSetParity(args.Parity))
  355.     { PrintError(line->Num, "invalid parity");
  356.     }
  357.   }
  358.   if (args.Protocol)
  359.   { if (!SerialSetProtocol(args.Protocol))
  360.     { PrintError(line->Num, "unknown protocol");
  361.     }
  362.   }
  363. }
  364.  
  365. #endif /* SETCMD */
  366.  
  367.  
  368.  
  369.  
  370. #ifdef SHOWPARMSCMD
  371.  
  372. /**
  373. ***  This function shows the serial.device parameters.
  374. **/
  375. VOID ShowParmsFunc(struct ScriptLine *line)
  376.  
  377. { if (!SerialDeviceName)
  378.   { PrintError(line->Num, "serial device not opened");
  379.   }
  380.  
  381.   printf("%s Parameters:\n\n", SerialDeviceName);
  382.   SerialShowParms();
  383. }
  384.  
  385. #endif /* SHOWPARMSCMD */
  386.  
  387.  
  388.  
  389.  
  390.  
  391. /**
  392. ***  This function sends a string to the serial.device.
  393. **/
  394. VOID SendFunc(struct ScriptLine *line)
  395.  
  396. { STRPTR args;
  397.  
  398.   if (!SerialDeviceName)
  399.   { PrintError(line->Num, "serial device not opened");
  400.   }
  401.  
  402.   if (!StrReadArgs(line->Args, (LONG *) &args, (STRPTR) "TEXT/A/F"))
  403.   { PrintError(line->Num, "argument or memory error");
  404.   }
  405.  
  406.   SerialSend(ParseString(args));
  407. }
  408.  
  409.  
  410.  
  411.  
  412.  
  413. /**
  414. ***  This is similar to "if".
  415. **/
  416. VOID DoGoto(STRPTR Label, int Num)
  417.  
  418. { struct ScriptLine *sl;
  419.  
  420.   for(sl = (struct ScriptLine *) ScriptLineList.mlh_Head;
  421.             sl->mn.mln_Succ;
  422.             sl = (struct ScriptLine *) sl->mn.mln_Succ)
  423.   { if (sl->Label  &&  strcmp((char *) sl->Label, (char *) Label) == 0)
  424.     { CurrentScriptLine = (struct ScriptLine *) sl->mn.mln_Pred;
  425.       return;
  426.     }
  427.   }
  428.  
  429.   PrintError(Num, "unknown label");
  430. }
  431. VOID OnFunc(struct ScriptLine *line)
  432.  
  433. { STRPTR ptr = line->Args;
  434.  
  435.   if (strnicmp((char *) ptr, "status", 6) == 0)
  436.   { ptr = SkipBlanks(ptr+6);
  437.     if (strnicmp((char *) ptr, "goto", 4) == 0)
  438.     { STRPTR *labels;
  439.       int i;
  440.  
  441.       if (!StrReadArgs(ptr+4, (LONG *) &labels, (STRPTR) "LABELS/A/M"))
  442.       { PrintError(line->Num, "argument or memory error");
  443.       }
  444.       for (i = -1;  *labels;  ++i, ++labels)
  445.       { if (i == StatusVar)
  446.         { DoGoto(*labels, line->Num);
  447.           return;
  448.         }
  449.       }
  450.       return;
  451.     }
  452.   }
  453.  
  454.   PrintError(line->Num, "syntax error");
  455. }
  456.  
  457.  
  458.  
  459.  
  460.  
  461. /**
  462. ***  This function waits for certain strings.
  463. **/
  464. VOID WaitFunc(struct ScriptLine *line)
  465.  
  466. { struct
  467.   { ULONG *TimeOut;
  468.     STRPTR *WaitArgs;
  469.   } args;
  470.  
  471.   STRPTR* parsedArgs;
  472.   LONG TimeOut;
  473.   int i = 0;
  474.  
  475.   if (!SerialDeviceName)
  476.   { PrintError(line->Num, "serial device not opened");
  477.   }
  478.  
  479.   args.WaitArgs = NULL;
  480.   args.TimeOut = NULL;
  481.  
  482.   if (!(StrReadArgs(line->Args, (LONG *) &args, (STRPTR) "TIMEOUT/K/N,TEXT/A/M")))
  483.   { PrintError(line->Num, "argument or memory error");
  484.   }
  485.  
  486.   if (args.TimeOut)
  487.   { TimeOut = *args.TimeOut;
  488.   }
  489.   else
  490.   { TimeOut = DEFAULT_TIMEOUT;
  491.   }
  492.  
  493.   while (args.WaitArgs[i])
  494.   { ++i;
  495.   }
  496.  
  497.   if (!(parsedArgs = malloc(sizeof(STRPTR) * (i+1))))
  498.   { PrintError(0, "not enough memory");
  499.   }
  500.  
  501.   for (i = 0;  args.WaitArgs[i];  i++)
  502.   { parsedArgs[i] = ParseString(args.WaitArgs[i]);
  503.   }
  504.   parsedArgs[i] = NULL;
  505.  
  506.   StatusVar = SerialWait(parsedArgs, TimeOut);
  507. }
  508.  
  509.  
  510.  
  511.  
  512.  
  513. /**
  514. ***  The delay function waits for a certain amount of time.
  515. **/
  516. VOID DelayFunc(struct ScriptLine *line)
  517.  
  518. { struct
  519.   { LONG *secs;
  520.     LONG *millisecs;
  521.   } args;
  522.  
  523.   args.secs = NULL;
  524.   args.millisecs = NULL;
  525.  
  526.   if (!StrReadArgs(line->Args, (LONG *) &args,
  527.                    (STRPTR) "SECS/A/N,MILLISECS/N"))
  528.   { PrintError(line->Num, "argument or memory error");
  529.   }
  530.  
  531.   if (*args.secs < 0)
  532.   { PrintError(line->Num, "invalid time");
  533.   }
  534.  
  535.   if (args.millisecs == NULL)
  536.   { TimerWait(*args.secs, 0L);
  537.   }
  538.   else
  539.   { if (*args.millisecs < 0)
  540.     { PrintError(line->Num, "invalid time");
  541.     }
  542.     TimerWait(*args.secs, *args.millisecs);
  543.   }
  544. }
  545.  
  546.  
  547.  
  548.  
  549.  
  550. /**
  551. ***  And this is the Exit function.
  552. **/
  553. VOID ExitFunc(struct ScriptLine *line)
  554.  
  555. { struct
  556.   { LONG *rc;
  557.   } args;
  558.  
  559.   args.rc = NULL;
  560.  
  561.   if (!StrReadArgs(line->Args, (LONG *) &args,
  562.                    (STRPTR) "RETURNCODE/N"))
  563.   { PrintError(line->Num, "argument or memory error");
  564.   }
  565.  
  566.   if (!args.rc)
  567.   { CleanupAndExit(0);
  568.   }
  569.  
  570.   if (*args.rc < 0 || *args.rc > 255)
  571.   { PrintError(line->Num, "invalid return code");
  572.   }
  573.  
  574.   CleanupAndExit(*args.rc);
  575. }
  576.  
  577.  
  578.  
  579.  
  580.  
  581. /**
  582. ***  The Goto command
  583. **/
  584. VOID GotoFunc(struct ScriptLine *line)
  585.  
  586. { STRPTR Label;
  587.  
  588.   if (!(StrReadArgs(line->Args, (LONG *) &Label, (STRPTR) "LABEL/A")))
  589.   { PrintError(line->Num, "argument or memory error");
  590.   }
  591.  
  592.   DoGoto(Label, line->Num);
  593. }
  594.  
  595.  
  596.  
  597.  
  598.  
  599. /**
  600. ***  This function enters terminal mode.
  601. **/
  602. VOID TermFunc(struct ScriptLine *line)
  603.  
  604. { struct
  605.   { STRPTR eof;
  606.     ULONG noecho;
  607.     ULONG raw;
  608.   } args;
  609.  
  610.   args.eof = NULL;
  611.   args.noecho = FALSE;
  612.   args.raw = FALSE;
  613.  
  614.   if (!StrReadArgs(line->Args, (LONG *) &args, (STRPTR) "EOF,NOECHO/S,RAW/S"))
  615.   { PrintError(line->Num, "argument or memory error");
  616.   }
  617.  
  618.   if (args.eof)
  619.   { args.eof = ParseString(args.eof);
  620.   }
  621.  
  622.   SerialTerminal(args.eof, !args.noecho, !args.raw);
  623. }
  624.  
  625.  
  626.  
  627.  
  628.  
  629. /**
  630. ***  Execute external commands.
  631. **/
  632. VOID SystemFunc(struct ScriptLine *line)
  633.  
  634. { STRPTR args;
  635.   int result;
  636.  
  637.   if (!StrReadArgs(line->Args, (LONG *) &args, (STRPTR) "COMMAND/A/F"))
  638.   { PrintError(line->Num, "argument or memory error");
  639.   }
  640.  
  641.   if (VerboseMode)
  642.   { printf(">>> Executing command: \"%s\"\n", args);
  643.   }
  644.  
  645.   result = system((char *) args);
  646.  
  647.   if (result)
  648.   { if (result > 1  &&  result < 10)  /* Warning */
  649.     { if (VerboseMode)
  650.       { printf(">>> Returned %ld.\n", result);
  651.       }
  652.     }
  653.     else
  654.     { if (VerboseMode)
  655.       { printf(">>> Returned %ld.\n", result);
  656.       }
  657.       PrintError(line->Num, "command returned with RC >=10");
  658.     }
  659.   }
  660. }
  661.  
  662.  
  663.  
  664.  
  665.  
  666. /**
  667. ***  Scan the buffer received by the last "wait" command.
  668. **/
  669. VOID ScanFunc(struct ScriptLine *line)
  670.  
  671. { struct
  672.   { STRPTR format;
  673.     ULONG global;
  674.     ULONG save;
  675.   } args;
  676.   ULONG flags;
  677.  
  678.   args.format = NULL;
  679.   args.global = FALSE;
  680.   args.save = FALSE;
  681.  
  682.   if (!(StrReadArgs(line->Args, (LONG *) &args,
  683.                     (STRPTR) "FORMAT/A,GLOBAL/S,SAVE/S")))
  684.   { PrintError(line->Num, "argument or memory error");
  685.   }
  686.  
  687.   flags = 0;
  688.   if (args.save)
  689.   { args.global = TRUE;
  690.     flags |= GVF_SAVE_VAR;
  691.   }
  692.   if (args.global)
  693.   { flags |= GVF_GLOBAL_ONLY;
  694.   }
  695.   else
  696.   { flags |= GVF_LOCAL_ONLY;
  697.   }
  698.  
  699.   StatusVar = Vsscanf(SerialWaitBuffer(), args.format, flags);
  700. }
  701.  
  702.  
  703.  
  704.  
  705. /**
  706. ***  The SetVar command
  707. **/
  708. void SetVarFunc(struct ScriptLine *line)
  709.  
  710. { struct {
  711.     STRPTR name;
  712.     STRPTR value;
  713.     ULONG global;
  714.     ULONG save;
  715.   } args;
  716.   int flags;
  717.  
  718.   args.name = NULL;
  719.   args.value = NULL;
  720.   args.global = FALSE;
  721.   args.save = FALSE;
  722.  
  723.   if (!(StrReadArgs(line->Args, (LONG *) &args,
  724.                     (STRPTR) "NAME/A,VALUE/A,GLOBAL/S,SAVE/S")))
  725.   { PrintError(line->Num, "argument or memory error");
  726.   }
  727.  
  728.   flags = 0;
  729.   if (args.save) {
  730.       flags |= GVF_SAVE_VAR;
  731.       args.global = TRUE;
  732.   }
  733.   if (args.global) {
  734.       flags |= GVF_GLOBAL_ONLY;
  735.   } else {
  736.       flags |= GVF_LOCAL_ONLY;
  737.   }
  738.  
  739.   SetVar(args.name, args.value, -1, LV_VAR | flags);
  740. }
  741.  
  742.  
  743.  
  744.  
  745. /**
  746. ***  This is the command table.
  747. **/
  748. struct Command CommandTab[] =
  749. { { EchoFunc,       (STRPTR) "echo"         },
  750.   { DeviceFunc,     (STRPTR) "device"       },
  751. #ifdef SETCMD
  752.   { SetFunc,        (STRPTR) "set"          },
  753. #endif
  754. #ifdef SHOWPARMSCMD
  755.   { ShowParmsFunc,  (STRPTR) "showparms"    },
  756. #endif
  757.   { SendFunc,       (STRPTR) "send"         },
  758.   { OnFunc,         (STRPTR) "on"           },
  759.   { WaitFunc,       (STRPTR) "wait"         },
  760.   { DelayFunc,      (STRPTR) "delay"        },
  761.   { ExitFunc,       (STRPTR) "exit"         },
  762.   { GotoFunc,       (STRPTR) "goto"         },
  763.   { TermFunc,       (STRPTR) "terminal"     },
  764.   { SystemFunc,     (STRPTR) "system"       },
  765.   { ScanFunc,       (STRPTR) "scan"         },
  766.   { SetVarFunc,     (STRPTR) "setvar"       },
  767.   { NULL,           NULL                    }
  768. };
  769.  
  770.  
  771.  
  772.  
  773.  
  774. /**
  775. ***  This function is used to process the file. Rather easy,
  776. ***  isn't it? :-)
  777. **/
  778. VOID ProcessFile(VOID)
  779.  
  780. { for(CurrentScriptLine = (struct ScriptLine *) ScriptLineList.mlh_Head;
  781.       CurrentScriptLine->mn.mln_Succ;
  782.       CurrentScriptLine = (struct ScriptLine *) CurrentScriptLine->mn.mln_Succ)
  783.   { (*CurrentScriptLine->CommFunc)(CurrentScriptLine);
  784.   }
  785. }
  786.  
  787.  
  788.  
  789.  
  790.  
  791. /**
  792. ***  This function reads and parses the file.
  793. **/
  794. VOID ParseFile(STRPTR file)
  795.  
  796. { FILE *fp;
  797.   ULONG linenum = 0;
  798.   ULONG success = TRUE;
  799.  
  800.   if (!(fp = fopen((char *) file, "r")))
  801.   { PrintError(0, "could not open dial script for reading");
  802.   }
  803.  
  804.   NewList((struct List *) &ScriptLineList);
  805.  
  806.   while(fgets((char *) ScratchBuffer, ScBufSize, fp))
  807.   { ULONG len = strlen((char *) ScratchBuffer);
  808.     STRPTR line;
  809.     STRPTR Label = NULL;
  810.     CommandFunc CommFunc;
  811.  
  812.     ++linenum;
  813.  
  814.     if (ScratchBuffer[len-1] != '\n')
  815.     { PrintError(linenum, "line too long");
  816.     }
  817.  
  818.     if (!(line = malloc(len+1)))
  819.     { PrintError(0, "not enough memory");
  820.     }
  821.     strcpy((char*) line, (char*) ScratchBuffer);
  822.     line = SkipBlanks(line);
  823.  
  824.     /**
  825.     ***  Check for a label
  826.     **/
  827.     { STRPTR ptr = line;
  828.  
  829.       if (isalpha(*ptr))
  830.       { do
  831.         { ++ptr;
  832.         }
  833.         while(isalnum(*ptr));
  834.  
  835.         if (*ptr == ':')
  836.         { *ptr = '\0';
  837.           Label = line;
  838.           line = SkipBlanks(ptr+1);
  839.         }
  840.       }
  841.     }
  842.  
  843.     /**
  844.     ***  Check for empty line or comment line
  845.     **/
  846.     if (*line == ';'  ||  *line == '\r'  ||  *line == '\n')
  847.     { CommFunc = NoneFunc;
  848.       if (!Label)
  849.       { continue;
  850.       }
  851.     }
  852.  
  853.     /**
  854.     ***  If no empty line: Check for command
  855.     **/
  856.     else
  857.     { struct Command *comm;
  858.  
  859.       for (comm = &CommandTab[0];  comm->Func;  ++comm)
  860.       { ULONG len = strlen((char *) comm->Name);
  861.  
  862.         if (strnicmp((char *) comm->Name, (char *) line, len) == 0  &&
  863.             (line[len] == ' '  ||  line[len] == '\t'  ||
  864.              line[len] == '\r' ||  line[len] == '\n'))
  865.         { line = SkipBlanks(line+len);
  866.           CommFunc = comm->Func;
  867.           break;
  868.         }
  869.       }
  870.  
  871.       if (!comm->Func)
  872.       { fprintf(stderr, "Line %ld: Unknown command - ignored\n", linenum);
  873.         success = FALSE;
  874.       }
  875.     }
  876.  
  877.     /**
  878.     ***  Allocate a new scriptline structure.
  879.     **/
  880.     { struct ScriptLine *sl;
  881.  
  882.       if (!(sl = malloc(sizeof(*sl))))
  883.       { PrintError(0, "not enough memory");
  884.       }
  885.  
  886.       AddTail((struct List *) &ScriptLineList, (struct Node *) sl);
  887.       sl->Num = linenum;
  888.       sl->CommFunc = CommFunc;
  889.       sl->Args = line;
  890.       sl->Label = Label;
  891.     }
  892.   }
  893.  
  894.   if (ferror(fp))
  895.   { PrintError(0, "not enough memory");
  896.   }
  897.  
  898.   if (!success)
  899.   { CleanupAndExit(5);
  900.   }
  901.  
  902.   fclose(fp);
  903. }
  904.  
  905.  
  906.  
  907.  
  908. /**
  909. ***  This is the error function; called, when an error occurs
  910. **/
  911. VOID PrintError(ULONG linenum, STRPTR errortext)
  912.  
  913. { if (linenum==0)
  914.   { fprintf(stderr, "\nInternal error: %s.\n", errortext);
  915.   }
  916.   else
  917.   { fprintf(stderr, "\nError in line %ld: %s.\n", linenum, errortext);
  918.   }
  919.   CleanupAndExit(10);
  920. }
  921.  
  922.  
  923.  
  924.  
  925. /**
  926. ***  This is the cleanup function; called, when the program terminates.
  927. **/
  928. VOID CleanupAndExit(int code)
  929.  
  930. { SerialCleanup();
  931.   StrReadArgsFree();
  932.   if (MainRDArgs)
  933.   { FreeArgs(MainRDArgs);
  934.   }
  935.   exit(code);
  936. }
  937.  
  938.  
  939.  
  940.  
  941.  
  942. /**
  943. ***  This function hints about the GPL.
  944. **/
  945. VOID ShowGPL(FILE *fp)
  946.  
  947. { fprintf(fp, "This program is governed by the terms and conditions of the\n");
  948.   fprintf(fp, "GNU General Public License. A copy should have come with\n");
  949.   fprintf(fp, "this distribution. (See the file COPYING.) In that license\n");
  950.   fprintf(fp, "it is made clear that you are welcome to redistribute either\n");
  951.   fprintf(fp, "verbatim or modified copies of the program and the documentation\n");
  952.   fprintf(fp, "under certain conditions. Further you are told that this program\n");
  953.   fprintf(fp, "comes with ABSOLUTELY NO WARRANTY!\n\n");
  954. }
  955.  
  956.  
  957.  
  958.  
  959.  
  960. /**
  961. ***  This function displays the Usage() message.
  962. **/
  963. VOID Usage(VOID)
  964.  
  965. { fprintf(stderr, "\n%s - written by Jochen Wiedmann and Stefan Gybas\n\n", VSTRING);
  966.   fprintf(stderr, "Usage:  IPDial SCRIPT,DEVICE/K,PROTOCOL/K,UNIT/K/N,BAUD/K/N,SANADEV/K,\n");
  967.   fprintf(stderr, "               TERMINAL/S,ECHO/S,VERBOSE/S,RAW/S,HELP/S\n\n");
  968.   fprintf(stderr, "\tSCRIPT:    Script file to execute [T]\n");
  969.   fprintf(stderr, "\tDEVICE:    Device to use (default: \"serial.device\") [T]\n");
  970.   fprintf(stderr, "\tPROTOCOL:  Protocol to use: XONXOFF, 7WIRE (default) or NONE [T]\n");
  971.   fprintf(stderr, "\tUNIT:      Unit to use (default 0) [T]\n");
  972.   fprintf(stderr, "\tBAUD:      Baud rate to use (default is taken from serial prefs) [T]\n");
  973.   fprintf(stderr, "\tSANADEV:   SANA config file to read serial config from [T,S]\n");
  974.   fprintf(stderr, "\tTERMINAL:  Run in terminal mode (i.e. don't execute script)\n");
  975.   fprintf(stderr, "\tECHO:      Show modem replies [S]\n");
  976.   fprintf(stderr, "\t           Use local echo mode [T]\n");
  977.   fprintf(stderr, "\tVERBOSE:   Show all operations the program performs [T,S]\n");
  978.   fprintf(stderr, "\tRAW:       Use character mode instead of line mode [T]\n\n");
  979.   fprintf(stderr, "\t[S]: argument is used in script mode\n");
  980.   fprintf(stderr, "\t[T]: argument is used in terminal mode\n\n");
  981.   ShowGPL(stderr);
  982.   CleanupAndExit(5);
  983. }
  984.  
  985.  
  986.  
  987.  
  988.  
  989. /**
  990. ***  This is main().
  991. **/
  992. int main(int argc, char *argv[])
  993.  
  994. { struct
  995.   { STRPTR script;
  996.     STRPTR device;
  997.     STRPTR protocol;
  998.     LONG *unit;
  999.     LONG *baud;
  1000.     STRPTR sanadev;
  1001.     ULONG terminal;
  1002.     ULONG echo;
  1003.     ULONG verbose;
  1004.     ULONG raw;
  1005.   } args;
  1006.  
  1007.   args.script = NULL;
  1008.   args.device = NULL;
  1009.   args.protocol = NULL;
  1010.   args.unit = NULL;
  1011.   args.baud = NULL;
  1012.   args.sanadev = NULL;
  1013.   args.terminal = FALSE;
  1014.   args.echo = FALSE;
  1015.   args.verbose = FALSE;
  1016.   args.raw = FALSE;
  1017.  
  1018.   if (!argc)    /*  No WB handling.     */
  1019.   { CleanupAndExit(-1);
  1020.   }
  1021.  
  1022.   if (!(MainRDArgs = ReadArgs((STRPTR) "SCRIPT,DEVICE/K,PROTOCOL/K,UNIT/K/N,"
  1023.                                                    "BAUD/K/N,SANADEV/K,TERMINAL/S,"
  1024.                                                     "ECHO/S,VERBOSE/S,RAW/S",
  1025.                               (LONG *) &args, NULL)))
  1026.   { fprintf(stderr, "Cannot parse command line.\n");
  1027.   }
  1028.  
  1029.   if (!args.script  &&  !args.terminal)
  1030.   { Usage();
  1031.   }
  1032.  
  1033.   EchoMode = args.echo;
  1034.   if (args.verbose)
  1035.   { VerboseMode = TRUE;
  1036.     printf(">>> %s  - verbose mode\n", VSTRING);
  1037.   }
  1038.  
  1039.   if(args.sanadev)
  1040.   { SerialDeviceName = (STRPTR) strdup(ReadSanaConfig(args.sanadev));
  1041.   }
  1042.  
  1043.   if (args.terminal)
  1044.   { if (!SerialDeviceName)
  1045.     { if (!(SerialDeviceName = (STRPTR) strdup((char *) args.device)))
  1046.       { PrintError(0, "not enough memory");
  1047.       }
  1048.  
  1049.       if (!SerialOpen(args.device,
  1050.                       args.unit ? *args.unit : DEFAULT_UNIT,
  1051.                       args.baud ? *args.baud : DEFAULT_BAUD,
  1052.                       args.protocol ? args.protocol : DEFAULT_PROTOCOL))
  1053.       { PrintError(0, "could not open device");
  1054.       }
  1055.     }
  1056.  
  1057.     SerialTerminal(NULL, EchoMode, !args.raw);
  1058.   }
  1059.   else if (args.script)
  1060.   { ParseFile(args.script);
  1061.     ProcessFile();
  1062.   }
  1063.  
  1064.   CleanupAndExit(0);
  1065. }
  1066.